package com.tianfei.crowd.mvc.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.access.AccessDeniedHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author: Herz
 * @date: 2021/7/20 15:06
 */

// 表示当前类是一个配置类
@Configuration

// 启用 web 环境下的权限控制功能
@EnableWebSecurity

// 启用全局方法权限控制功能，并设置 prePostEnabled = true ，
// 保证 @PrePreAuthorize、@PostPreAuthorize、@PreFilter、@PostFilter 注解生效
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebAppSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    CrowdUserDetailsService userDetailsService;

    @Bean
    public BCryptPasswordEncoder getBCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder builder) throws Exception {

        // 使用基于内存版登录的账号、密码检测
        // builder.inMemoryAuthentication().withUser("tom").password("123456").roles("ADMIN");


        // 使用基于数据库登录的账号、密码检测
        // BCryptPasswordEncoder 盐值加密
        builder.userDetailsService(userDetailsService).passwordEncoder(getBCryptPasswordEncoder());
    }

    @Override
    protected void configure(HttpSecurity security) throws Exception {

        security
                .authorizeRequests()                    // 对请求授权
                .antMatchers("/admin-login-to-page.html")       // 针对登录页进行设置
                .permitAll()                                                // 可以无条件访问
                .antMatchers("/bootstrap/**")              // 针对静态资源进行设置，可以无条件访问
                .permitAll()
                .antMatchers("/crowd/**")
                .permitAll()
                .antMatchers("/css/**")
                .permitAll()
                .antMatchers("/fonts/**")
                .permitAll()
                .antMatchers("/img/**")
                .permitAll()
                .antMatchers("/jquery/**")
                .permitAll()
                .antMatchers("/layer/**")
                .permitAll()
                .antMatchers("/script/**")
                .permitAll()
                .antMatchers("/ztree/**")
                .permitAll()

                .antMatchers("/admin-to-user-page.html") // 针对 Admin分页数据 设定访问控制
//                .hasRole("经理")                                      // 具备“经理”角色
                .access("hasRole('经理') or hasAuthority('user:get')")


                .anyRequest()                                           // 其他任意请求
                .authenticated()                                        // 认证后才能访问


                .and()
                .csrf()                                              // 防跨站请求伪造功能
                .disable()                                          // 禁用
                .formLogin()                                         // 使用表单形式登录
                .loginPage("/admin-login-to-page.html")                        // 指定默认的登录页
                .permitAll()
                .loginProcessingUrl("/security-do-login-page.html")  // 指定处理登录请求的地址
                .permitAll()
                .usernameParameter("login_acct")                     // 指定登录账号的 请求参数名
                .passwordParameter("login_password")                 // 指定登录密码的 请求参数名
                .defaultSuccessUrl("/admin-main-to-page.html")       // 登录成功后前往的地址

                .and()
                .logout()                                           // 开启退出功能
                .logoutUrl("/security-do-logout-page.html")         // 处理退出请求的地址
                .logoutSuccessUrl("/admin-login-to-page.html")      // 成功退出后页面跳转的地址

                .and()
                .exceptionHandling()                                // 指定异常处理器
//                .accessDeniedPage("/visit-error-page.html")       // 访问被拒绝时前往的页面

                .accessDeniedHandler(new AccessDeniedHandler() {     // 自定义访问被拒绝时的行为
                    @Override
                    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {
                        httpServletRequest.setAttribute("exception", "抱歉！您没有该权限！");
                        httpServletRequest.getRequestDispatcher("/to-system-error-page.html").forward(httpServletRequest, httpServletResponse);
                    }
                })
        ;


    }
}
